package com.ruoyi.web.controller.monitor;


import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;



public class FileHeaderUtils {
    /**
     * 文件类型和文件大小校验
     *
     * @param file            上传的附件
     * @param allowedFileType 限制上传附件的类型
     */
    public static String checkFileHeader(MultipartFile file, Set<String> allowedFileType) throws InvalidExtensionException {
        // 去掉了后缀校验和大小校验
        String fileType;
        String fileName = file.getOriginalFilename();
        // 为了防止报错增加的两个变量
        String fileHeader = "其他类型";
        String[] alloweds = new String[allowedFileType.size()];
        // 给alloweds赋值
        int i = 0;
        for (String s : allowedFileType) {
            alloweds[i] = s;
            i++;
        }
        // 文件类型判断 - 校验文件头内容
        try (InputStream inputStream = file.getInputStream()) {
            // 获取到上传文件的文件头信息
            fileHeader = FileHeaderUtils.getFileHeader(inputStream);

            if (StringUtils.isBlank(fileHeader)) {
//                log.error("Failed to get file header content.");
                throw new InvalidExtensionException(alloweds, fileHeader, fileName);
//                throw new CommonException(BizCodeEnum.FILE_UPLOAD_TYPE_NOT_ALLOWED);
            }
            // 根据上传文件的文件头获取文件的真实类型
            fileType = getFileType(fileHeader);
            if (StringUtils.isBlank(fileType) || !fileTypeAllowed(fileType, allowedFileType)) {
//                log.error("Unsupported file type: [{}]", fileType);
                throw new InvalidExtensionException(alloweds, fileType, fileName);
//                throw new CommonException(BizCodeEnum.FILE_UPLOAD_TYPE_NOT_ALLOWED);
            }
        } catch (IOException | InvalidExtensionException e) {
//            log.error("Get file input stream failed.", e);
            throw new InvalidExtensionException(alloweds, fileHeader, fileName);
//            throw new CommonException(BizCodeEnum.ATTACHMENT_UPLOAD_ERROR);
        }
        return fileType;
    }

    /**
     * 文件类型校验
     *
     * @param fileType    待校验的类型
     * @param allowedType 允许上传的文件类型
     * @return true - 满足，false - 不满足
     */
    private static boolean fileTypeAllowed(String fileType, Set<String> allowedType) {
        if (StringUtils.isBlank(fileType) || CollectionUtils.isEmpty(allowedType)) {
            return false;
        }
        return allowedType.contains(fileType);
    }

    /**
     * 据文件的头信息获取文件类型
     *
     * @param fileHeader 文件头信息
     * @return 文件类型
     */
    public static String getFileType(String fileHeader) {
        if (fileHeader == null || fileHeader.length() == 0) {
            return null;
        }
        fileHeader = fileHeader.toUpperCase();
        FileTypeEnum[] fileTypes = FileTypeEnum.values();
        for (FileTypeEnum type : fileTypes) {
            boolean b = fileHeader.startsWith(type.getHeadCode());
            if (b) {
                return type.getSuffixName();
            }
        }
        return null;
    }

    /**
     * 文件头字节数组转为十六进制编码
     *
     * @param content 文件头字节数据
     * @return 十六进制编码
     */
    private static String bytesToHexString(byte[] content) {
        StringBuilder builder = new StringBuilder();
        if (content == null || content.length <= 0) {
            return null;
        }
        String temp;
        for (byte b : content) {
            temp = Integer.toHexString(b & 0xFF).toUpperCase();
            if (temp.length() < 2) {
                builder.append(0);
            }
            builder.append(temp);
        }
        return builder.toString();
    }

    /**
     * 获取文件的文件头信息
     *
     * @param inputStream 输入流
     * @return 文件头信息
     * @throws IOException 异常
     */
    private static String getFileHeader(InputStream inputStream) throws IOException {
        byte[] content = new byte[28];
        inputStream.read(content, 0, content.length);
        return bytesToHexString(content);
    }

}
